﻿/*
COPYRIGHT (C) 2010 EPISERVER AB

THIS FILE IS PART OF SCRUM DASHBOARD.

SCRUM DASHBOARD IS FREE SOFTWARE: YOU CAN REDISTRIBUTE IT AND/OR MODIFY IT UNDER THE TERMS OF 
THE GNU LESSER GENERAL PUBLIC LICENSE VERSION v2.1 AS PUBLISHED BY THE FREE SOFTWARE FOUNDATION.

SCRUM DASHBOARD IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY WARRANTY; WITHOUT
EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU LESSER
GENERAL PUBLIC LICENSE FOR MORE DETAILS.

YOU SHOULD HAVE RECEIVED A COPY OF THE GNU LESSER GENERAL PUBLIC LICENSE ALONG WITH SCRUM DASHBOARD. 
IF NOT, SEE <HTTP://WWW.GNU.ORG/LICENSES/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ScrumDashboard.Library.Tfs;
using System.ComponentModel.DataAnnotations;
using ScrumDashboard.Library.Models;
using ScrumDashboardMvc.Models;
using System.Configuration;
using ScrumDashboard.Library.Data;

namespace ScrumDashboardMvc.Controllers
{
    [HandleError, Authorize]
    public class DashboardController : Controller
    {
        IRepository _repo;

        public DashboardController()
            : this(RepositoryFactory.GetRespository())
        {
        }
        public DashboardController(IRepository repo)
        {
            _repo = repo;
        }

        [HttpGet]
        public ActionResult Index(string project, int sprint, int? teamsprint)
        {
            ISprintHandler sp = _repo.GetHandler<ISprintHandler>();
            var projs = _repo.GetHandler<IProjectHandler>().GetProjects();

            var tvd = new ToolbarViewData(projs.Where(p=>p.IsScrumProject==true).Select(p=>p), sp.GetSprints(project), _repo.GetHandler<ITeamSprintHandler>().GetTeamSprints(project, sprint), _repo.CurrentUser.DisplayName);
            tvd.AddSelection(tvd.Projects, project);
            tvd.AddSelection(tvd.Sprints, sprint);
            tvd.AddSelection(tvd.Teams, teamsprint);

            var dvd = new DashboardViewData
            {
                Toolbar = tvd,
                Sprint = SprintViewData.Create(_repo, project, sprint, teamsprint),
                Initials = _repo.CurrentUser.Initials,
                AllProjects = new SelectList((new TeamProject[]{new TeamProject{Name=""}}).Concat(projs), "Name", "Name")
            };

            return View(dvd);
        }

        [HttpPost]
        public ActionResult Sprints(string projectName)
        {
            return Json(_repo.GetHandler<ISprintHandler>().GetSprints(projectName));
        }

        [HttpPost]
        public ActionResult Overview(string project, int sprint, int? teamsprint)
        {
            IProjectHandler ph = _repo.GetHandler<IProjectHandler>();
            TeamProject proj = ph.GetProject(project);
            return View(OverviewViewData.Create(proj,SprintViewData.Create(_repo, project, sprint, teamsprint)));
        }

        [HttpPost]
        public ActionResult TeamSprints(string projectName, int sprint)
        {
            return Json(_repo.GetHandler<ITeamSprintHandler>().GetTeamSprints(projectName, sprint));
        }

        [HttpGet]
        public bool IsLatestVersion(int workItemID, int workItemRevisionID)
        {
            return false;
        }

        [HttpPost]
        public ActionResult SaveNewTaskDialog(string BacklogType)
        {
            BacklogItem item = BacklogItem.CreateType(BacklogType);
            
            if (!TryUpdateModel(item.GetType(), item, "ProductBacklogId", "Title", "EstimatedEffort", "Description"))
            {
                return View("NewTaskDialog", item);
            }

            if (!ModelState.IsValid)
            {
                throw new Exception("Failed to bind model, is the input invalid somehow ?");
            }

            IBacklogItemHandler backlogs = _repo.GetHandler<IBacklogItemHandler>();

            int workItemId = backlogs.CreateBacklogItem(item);

            item = backlogs.GetBacklogItem(workItemId);

            return View("DisplayTemplates/" + item.BacklogType.ToString() + "Template", item);
        }

        [HttpPost]
        public ActionResult SaveNewProductBacklogItemDialog(int sprint, int? teamsprint)
        {
            ProductBacklogItem pbi = new ProductBacklogItem();

            if (!TryUpdateModel(typeof(ProductBacklogItem), pbi, "Title", "StoryPoints", "Description"))
            {
                return Json(0);
            }

            if (!ModelState.IsValid)
            {
                throw new Exception("Failed to bind model, is the input invalid somehow ?");
            }

            IProductBacklogItemHandler pb = _repo.GetHandler<IProductBacklogItemHandler>();

            if (teamsprint.HasValue)
            {
                ITeamSprintHandler teamSprintHandler = _repo.GetHandler<ITeamSprintHandler>();
                TeamSprint teamSprintObj = teamSprintHandler.GetTeamSprint(teamsprint.Value);
                pbi.Project = teamSprintObj.Project;
                pbi.IterationPath = teamSprintObj.IterationPath;
            }
            else
            {
                ISprintHandler sprintHandler = _repo.GetHandler<ISprintHandler>();
                Sprint sprintObj = sprintHandler.GetSprint(sprint);
                pbi.Project = sprintObj.Project;
                pbi.IterationPath = sprintObj.IterationPath;
            }

            int workItemId = pb.CreateProductBacklogItem(pbi);

            return Json(workItemId);
        }

        [HttpPost]
        public ActionResult Queries(string projectName)
        {
            IProjectHandler proj = _repo.GetHandler<IProjectHandler>();

            return Json(proj.GetQueries(projectName));
        }

        [HttpPost]
        public ActionResult ImportTasks(int productBacklogId, string backlogType, int []workItemId)
        {
            IBacklogItemHandler backlog = _repo.GetHandler<IBacklogItemHandler>();

            if (workItemId == null || workItemId.Length == 0)
            {
                return View(new List<BacklogItem>());
            }
            IEnumerable<BacklogItem> items = backlog.ImportWorkItemsToBacklog(productBacklogId, (BacklogItemType)Enum.Parse(typeof(BacklogItemType), backlogType), workItemId);

            return View(items);
        }

        [HttpPost]
        public ActionResult AddProductBacklogItems(int sprint, int? teamsprint, int[] workItemId)
        {
            if (workItemId == null || workItemId.Length == 0)
            {
                return Json(true);
            }

            IProjectHandler proj = _repo.GetHandler<IProjectHandler>();

            string iterationPath;
            if (teamsprint.HasValue)
            {
                ITeamSprintHandler teamSprintHandler = _repo.GetHandler<ITeamSprintHandler>();
                TeamSprint teamSprintObj = teamSprintHandler.GetTeamSprint(teamsprint.Value);
                iterationPath = teamSprintObj.IterationPath;
            }
            else
            {
                ISprintHandler sprintHandler = _repo.GetHandler<ISprintHandler>();
                Sprint sprintObj = sprintHandler.GetSprint(sprint);
                iterationPath = sprintObj.IterationPath;
            }

            proj.SetIterationPath(workItemId, iterationPath);

            return Json(true);
        }


        [HttpPost]
        public ActionResult RunQuery(string projectName, Guid queryId)
        {
            IProjectHandler proj = _repo.GetHandler<IProjectHandler>();

            return Json(proj.RunQuery(projectName, queryId).ToList());
        }

        [HttpPost]
        public ActionResult MoveToState(int workItemID, string state)
        {
            IBacklogItemHandler backlogs = _repo.GetHandler<IBacklogItemHandler>();
            var item = backlogs.GetBacklogItem(workItemID);
            
            bool wasMoved = backlogs.MoveToState(workItemID, state, String.IsNullOrEmpty(item.AssignedTo.AccountName) ? _repo.CurrentUser.DisplayName : null);

            return Json(wasMoved);
        }

        [HttpPost]
        public void UpdateWorkRemaining(int workItemId, float workRemaining)
        {
            try
            {
                _repo.GetHandler<IBacklogItemHandler>().UpdateWorkRemaining(workItemId, workRemaining);
            }
            catch (Exception ex)
            {
                throw new Exception("Problem with set time for the item", ex);
            }
        }

        private bool TryUpdateModel(Type modelType, object model, params string[] includeProperties)
        {
            IModelBinder binder = this.Binders.GetBinder(modelType);
            ModelBindingContext bindingContext = new ModelBindingContext();
            bindingContext.ModelName = "";
            bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, modelType);
            bindingContext.ModelState = this.ModelState;
            bindingContext.PropertyFilter = (propertyName) => includeProperties.Contains(propertyName);
            bindingContext.ValueProvider = ValueProvider;

            binder.BindModel(ControllerContext, bindingContext);
            return this.ModelState.IsValid;
        }
    }
}
